home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / test / worm.c < prev    next >
C/C++ Source or Header  |  2002-10-24  |  10KB  |  428 lines

  1. /*
  2.  
  3.      @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
  4.      @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
  5.      @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
  6.      @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
  7.      @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
  8.      @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
  9.       @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
  10.        @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
  11.         @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
  12.  
  13.                  Eric P. Scott
  14.               Caltech High Energy Physics
  15.                  October, 1980
  16.  
  17.         Hacks to turn this into a test frame for cursor movement:
  18.             Eric S. Raymond <esr@snark.thyrsus.com>
  19.                 January, 1995
  20.  
  21.         July 1995 (esr): worms is now in living color! :-)
  22.  
  23. Options:
  24.     -f            fill screen with copies of 'WORM' at start.
  25.     -l <n>            set worm length
  26.     -n <n>            set number of worms
  27.     -t            make worms leave droppings
  28.     -T <start> <end>    set trace interval
  29.     -S            set single-stepping during trace interval
  30.     -N            suppress cursor-movement optimization
  31.  
  32.   This program makes a good torture-test for the ncurses cursor-optimization
  33.   code.  You can use -T to set the worm move interval over which movement
  34.   traces will be dumped.  The program stops and waits for one character of
  35.   input at the beginning and end of the interval.
  36.  
  37.   $Id: worm.c,v 1.37 2002/06/29 23:32:18 tom Exp $
  38. */
  39.  
  40. #include <test.priv.h>
  41.  
  42. static chtype flavor[] =
  43. {
  44.     'O', '*', '#', '$', '%', '0', '@',
  45. };
  46. static const short xinc[] =
  47. {
  48.     1, 1, 1, 0, -1, -1, -1, 0
  49. }, yinc[] =
  50. {
  51.     -1, 0, 1, 1, 1, 0, -1, -1
  52. };
  53. static struct worm {
  54.     int orientation, head;
  55.     short *xpos, *ypos;
  56. } worm[40];
  57.  
  58. static const char *field;
  59. static int length = 16, number = 3;
  60. static chtype trail = ' ';
  61.  
  62. #ifdef TRACE
  63. int generation, trace_start, trace_end, singlestep;
  64. #endif /* TRACE */
  65. /* *INDENT-OFF* */
  66. static const struct options {
  67.     int nopts;
  68.     int opts[3];
  69. } normal[8]={
  70.     { 3, { 7, 0, 1 } },
  71.     { 3, { 0, 1, 2 } },
  72.     { 3, { 1, 2, 3 } },
  73.     { 3, { 2, 3, 4 } },
  74.     { 3, { 3, 4, 5 } },
  75.     { 3, { 4, 5, 6 } },
  76.     { 3, { 5, 6, 7 } },
  77.     { 3, { 6, 7, 0 } }
  78. }, upper[8]={
  79.     { 1, { 1, 0, 0 } },
  80.     { 2, { 1, 2, 0 } },
  81.     { 0, { 0, 0, 0 } },
  82.     { 0, { 0, 0, 0 } },
  83.     { 0, { 0, 0, 0 } },
  84.     { 2, { 4, 5, 0 } },
  85.     { 1, { 5, 0, 0 } },
  86.     { 2, { 1, 5, 0 } }
  87. }, left[8]={
  88.     { 0, { 0, 0, 0 } },
  89.     { 0, { 0, 0, 0 } },
  90.     { 0, { 0, 0, 0 } },
  91.     { 2, { 2, 3, 0 } },
  92.     { 1, { 3, 0, 0 } },
  93.     { 2, { 3, 7, 0 } },
  94.     { 1, { 7, 0, 0 } },
  95.     { 2, { 7, 0, 0 } }
  96. }, right[8]={
  97.     { 1, { 7, 0, 0 } },
  98.     { 2, { 3, 7, 0 } },
  99.     { 1, { 3, 0, 0 } },
  100.     { 2, { 3, 4, 0 } },
  101.     { 0, { 0, 0, 0 } },
  102.     { 0, { 0, 0, 0 } },
  103.     { 0, { 0, 0, 0 } },
  104.     { 2, { 6, 7, 0 } }
  105. }, lower[8]={
  106.     { 0, { 0, 0, 0 } },
  107.     { 2, { 0, 1, 0 } },
  108.     { 1, { 1, 0, 0 } },
  109.     { 2, { 1, 5, 0 } },
  110.     { 1, { 5, 0, 0 } },
  111.     { 2, { 5, 6, 0 } },
  112.     { 0, { 0, 0, 0 } },
  113.     { 0, { 0, 0, 0 } }
  114. }, upleft[8]={
  115.     { 0, { 0, 0, 0 } },
  116.     { 0, { 0, 0, 0 } },
  117.     { 0, { 0, 0, 0 } },
  118.     { 0, { 0, 0, 0 } },
  119.     { 0, { 0, 0, 0 } },
  120.     { 1, { 3, 0, 0 } },
  121.     { 2, { 1, 3, 0 } },
  122.     { 1, { 1, 0, 0 } }
  123. }, upright[8]={
  124.     { 2, { 3, 5, 0 } },
  125.     { 1, { 3, 0, 0 } },
  126.     { 0, { 0, 0, 0 } },
  127.     { 0, { 0, 0, 0 } },
  128.     { 0, { 0, 0, 0 } },
  129.     { 0, { 0, 0, 0 } },
  130.     { 0, { 0, 0, 0 } },
  131.     { 1, { 5, 0, 0 } }
  132. }, lowleft[8]={
  133.     { 3, { 7, 0, 1 } },
  134.     { 0, { 0, 0, 0 } },
  135.     { 0, { 0, 0, 0 } },
  136.     { 1, { 1, 0, 0 } },
  137.     { 2, { 1, 7, 0 } },
  138.     { 1, { 7, 0, 0 } },
  139.     { 0, { 0, 0, 0 } },
  140.     { 0, { 0, 0, 0 } }
  141. }, lowright[8]={
  142.     { 0, { 0, 0, 0 } },
  143.     { 1, { 7, 0, 0 } },
  144.     { 2, { 5, 7, 0 } },
  145.     { 1, { 5, 0, 0 } },
  146.     { 0, { 0, 0, 0 } },
  147.     { 0, { 0, 0, 0 } },
  148.     { 0, { 0, 0, 0 } },
  149.     { 0, { 0, 0, 0 } }
  150. };
  151. /* *INDENT-ON* */
  152.  
  153. static void
  154. cleanup(void)
  155. {
  156.     standend();
  157.     refresh();
  158.     curs_set(1);
  159.     endwin();
  160. }
  161.  
  162. static RETSIGTYPE
  163. onsig(int sig GCC_UNUSED)
  164. {
  165.     cleanup();
  166.     ExitProgram(EXIT_FAILURE);
  167. }
  168.  
  169. static float
  170. ranf(void)
  171. {
  172.     long r = (rand() & 077777);
  173.     return ((float) r / 32768.);
  174. }
  175.  
  176. int
  177. main(int argc, char *argv[])
  178. {
  179.     short **ref;
  180.     int x, y;
  181.     int n;
  182.     struct worm *w;
  183.     const struct options *op;
  184.     int h;
  185.     short *ip;
  186.     int last, bottom;
  187.  
  188.     setlocale(LC_ALL, "");
  189.  
  190.     for (x = 1; x < argc; x++) {
  191.     char *p;
  192.     p = argv[x];
  193.     if (*p == '-')
  194.         p++;
  195.     switch (*p) {
  196.     case 'f':
  197.         field = "WORM";
  198.         break;
  199.     case 'l':
  200.         if (++x == argc)
  201.         goto usage;
  202.         if ((length = atoi(argv[x])) < 2 || length > 1024) {
  203.         fprintf(stderr, "%s: Invalid length\n", *argv);
  204.         ExitProgram(EXIT_FAILURE);
  205.         }
  206.         break;
  207.     case 'n':
  208.         if (++x == argc)
  209.         goto usage;
  210.         if ((number = atoi(argv[x])) < 1 || number > 40) {
  211.         fprintf(stderr, "%s: Invalid number of worms\n", *argv);
  212.         ExitProgram(EXIT_FAILURE);
  213.         }
  214.         break;
  215.     case 't':
  216.         trail = '.';
  217.         break;
  218. #ifdef TRACE
  219.     case 'S':
  220.         singlestep = TRUE;
  221.         break;
  222.     case 'T':
  223.         trace_start = atoi(argv[++x]);
  224.         trace_end = atoi(argv[++x]);
  225.         break;
  226.     case 'N':
  227.         _nc_optimize_enable ^= OPTIMIZE_ALL;    /* declared by ncurses */
  228.         break;
  229. #endif /* TRACE */
  230.     default:
  231.       usage:
  232.         fprintf(stderr,
  233.             "usage: %s [-field] [-length #] [-number #] [-trail]\n", *argv);
  234.         ExitProgram(EXIT_FAILURE);
  235.     }
  236.     }
  237.  
  238.     signal(SIGINT, onsig);
  239.     initscr();
  240.     noecho();
  241.     cbreak();
  242.     nonl();
  243.  
  244.     curs_set(0);
  245.  
  246.     bottom = LINES - 1;
  247.     last = COLS - 1;
  248.  
  249. #ifdef A_COLOR
  250.     if (has_colors()) {
  251.     int bg = COLOR_BLACK;
  252.     start_color();
  253. #if HAVE_USE_DEFAULT_COLORS
  254.     if (use_default_colors() == OK)
  255.         bg = -1;
  256. #endif
  257.  
  258. #define SET_COLOR(num, fg) \
  259.         init_pair(num+1, fg, bg); \
  260.         flavor[num] |= COLOR_PAIR(num+1) | A_BOLD
  261.  
  262.     SET_COLOR(0, COLOR_GREEN);
  263.     SET_COLOR(1, COLOR_RED);
  264.     SET_COLOR(2, COLOR_CYAN);
  265.     SET_COLOR(3, COLOR_WHITE);
  266.     SET_COLOR(4, COLOR_MAGENTA);
  267.     SET_COLOR(5, COLOR_BLUE);
  268.     SET_COLOR(6, COLOR_YELLOW);
  269.     }
  270. #endif /* A_COLOR */
  271.  
  272.     ref = typeMalloc(short *, LINES);
  273.     for (y = 0; y < LINES; y++) {
  274.     ref[y] = typeMalloc(short, COLS);
  275.     for (x = 0; x < COLS; x++) {
  276.         ref[y][x] = 0;
  277.     }
  278.     }
  279.  
  280. #ifdef BADCORNER
  281.     /* if addressing the lower right corner doesn't work in your curses */
  282.     ref[bottom][last] = 1;
  283. #endif /* BADCORNER */
  284.  
  285.     for (n = number, w = &worm[0]; --n >= 0; w++) {
  286.     w->orientation = w->head = 0;
  287.     if (!(ip = typeMalloc(short, (length + 1)))) {
  288.         fprintf(stderr, "%s: out of memory\n", *argv);
  289.         ExitProgram(EXIT_FAILURE);
  290.     }
  291.     w->xpos = ip;
  292.     for (x = length; --x >= 0;)
  293.         *ip++ = -1;
  294.     if (!(ip = typeMalloc(short, (length + 1)))) {
  295.         fprintf(stderr, "%s: out of memory\n", *argv);
  296.         ExitProgram(EXIT_FAILURE);
  297.     }
  298.     w->ypos = ip;
  299.     for (y = length; --y >= 0;)
  300.         *ip++ = -1;
  301.     }
  302.     if (field) {
  303.     const char *p;
  304.     p = field;
  305.     for (y = bottom; --y >= 0;) {
  306.         for (x = COLS; --x >= 0;) {
  307.         addch((chtype) (*p++));
  308.         if (!*p)
  309.             p = field;
  310.         }
  311.     }
  312.     }
  313.     napms(10);
  314.     refresh();
  315. #ifndef TRACE
  316.     nodelay(stdscr, TRUE);
  317. #endif
  318.  
  319.     for (;;) {
  320. #ifdef TRACE
  321.     if (trace_start || trace_end) {
  322.         if (generation == trace_start) {
  323.         trace(TRACE_CALLS);
  324.         getch();
  325.         } else if (generation == trace_end) {
  326.         trace(0);
  327.         getch();
  328.         }
  329.  
  330.         if (singlestep && generation > trace_start && generation < trace_end)
  331.         getch();
  332.  
  333.         generation++;
  334.     }
  335. #else
  336.     int ch;
  337.  
  338.     if ((ch = getch()) > 0) {
  339. #ifdef KEY_RESIZE
  340.         if (ch == KEY_RESIZE) {
  341.         if (last != COLS - 1) {
  342.             for (y = 0; y <= bottom; y++) {
  343.             ref[y] = typeRealloc(short, COLS, ref[y]);
  344.             for (x = last + 1; x < COLS; x++)
  345.                 ref[y][x] = 0;
  346.             }
  347.             last = COLS - 1;
  348.         }
  349.         if (bottom != LINES - 1) {
  350.             for (y = LINES; y <= bottom; y++)
  351.             free(ref[y]);
  352.             ref = typeRealloc(short *, LINES, ref);
  353.             for (y = bottom + 1; y < LINES; y++) {
  354.             ref[y] = typeMalloc(short, COLS);
  355.             for (x = 0; x < COLS; x++)
  356.                 ref[y][x] = 0;
  357.             }
  358.             bottom = LINES - 1;
  359.         }
  360.         }
  361. #endif
  362.         /*
  363.          * Make it simple to put this into single-step mode, or resume
  364.          * normal operation -TD
  365.          */
  366.         if (ch == 'q') {
  367.         cleanup();
  368.         ExitProgram(EXIT_SUCCESS);
  369.         } else if (ch == 's') {
  370.         nodelay(stdscr, FALSE);
  371.         } else if (ch == ' ') {
  372.         nodelay(stdscr, TRUE);
  373.         }
  374.     }
  375. #endif /* TRACE */
  376.  
  377.     for (n = 0, w = &worm[0]; n < number; n++, w++) {
  378.         if ((x = w->xpos[h = w->head]) < 0) {
  379.         move(y = w->ypos[h] = bottom, x = w->xpos[h] = 0);
  380.         addch(flavor[n % SIZEOF(flavor)]);
  381.         ref[y][x]++;
  382.         } else {
  383.         y = w->ypos[h];
  384.         }
  385.         if (x > last)
  386.         x = last;
  387.         if (y > bottom)
  388.         y = bottom;
  389.         if (++h == length)
  390.         h = 0;
  391.         if (w->xpos[w->head = h] >= 0) {
  392.         int x1, y1;
  393.         x1 = w->xpos[h];
  394.         y1 = w->ypos[h];
  395.         if (y1 < LINES
  396.             && x1 < COLS
  397.             && --ref[y1][x1] == 0) {
  398.             move(y1, x1);
  399.             addch(trail);
  400.         }
  401.         }
  402.         op = &(x == 0 ? (y == 0 ? upleft : (y == bottom ? lowleft :
  403.                         left)) :
  404.            (x == last ? (y == 0 ? upright : (y == bottom ? lowright :
  405.                              right)) :
  406.             (y == 0 ? upper : (y == bottom ? lower : normal))))[w->orientation];
  407.         switch (op->nopts) {
  408.         case 0:
  409.         cleanup();
  410.         ExitProgram(EXIT_SUCCESS);
  411.         case 1:
  412.         w->orientation = op->opts[0];
  413.         break;
  414.         default:
  415.         w->orientation = op->opts[(int) (ranf() * (float) op->nopts)];
  416.         }
  417.         move(y += yinc[w->orientation], x += xinc[w->orientation]);
  418.  
  419.         if (y < 0)
  420.         y = 0;
  421.         addch(flavor[n % SIZEOF(flavor)]);
  422.         ref[w->ypos[h] = y][w->xpos[h] = x]++;
  423.     }
  424.     napms(10);
  425.     refresh();
  426.     }
  427. }
  428.